# -*- coding: utf-8 -*-
# @Time    : 2016/10/24
from sympy import solveset, FiniteSet
from mathsolver.functions.base import BaseNumber
from mathsolver.functions.daoshu.jizhi import *


class HanShuQuJianZuiDaZhi(BaseFunction):
    """"求函数在区间上的最大值"""
    zuizhi_func = max
    symbol = "最大值"

    def solver(self, *args):
        fun = args[0]
        interval = args[1].interval
        start, end = interval.start, interval.end

        # 求函数导数
        deriv = HanShuDaoShuYunSuan().solver(fun).output[0]
        self.steps.append(["因为 {}".format(fun.printing()),
                           "求导得 {}".format(deriv.printing())])

        # 令 f'(x) = 0
        jizhi = solveset(deriv.expression, deriv.var, S.Reals)

        if not jizhi:  # 如果f'(x) = 0 无解
            # 则函数在区间上单调递增或递减

            deriv_gt_0 = deriv.expression.subs(deriv.var, (start + end) / 2.0) > 0
            greater_or_less = '>' if deriv_gt_0 else '<'
            zeng_or_jian = '递增' if deriv_gt_0 else '递减'
            self.steps.append(["因为 {} {} 0".format(deriv.printing(), greater_or_less),
                               "所以函数在区间 {} 上单调{}".format(args[1].printing(), zeng_or_jian)])

            if self.symbol == "最大值":
                x = end if deriv_gt_0 else end
            elif self.symbol == "最小值":
                x = start if deriv_gt_0 else end
            else:
                raise Exception("to do")

            zuizhi = fun.expression.subs(fun.var, x)

            # 补充：如果取到最值
            if x in interval:
                self.steps.append(['函数在 x = {} 处取得{}'.format(x, self.symbol),
                                   '且{}({})={}'.format(fun.name, x, zuizhi)])
            else:
                self.steps.append(["", "最值点 %s 不在区间 %s 内，所以函数不存在%s" % (x, interval, self.symbol)])
                zuizhi = None

        else:
            self.steps.append(["求函数的极值点：令{0}'({1}) = 0".format(fun.name, fun.var),
                               "得 {0} = {1}".format(fun.var, " 或 ".join([str(e) for e in jizhi]))])

            # 筛选出区间内的极值点
            jizhi_filtered = [x for x in jizhi if start < x < end]
            jizhi_outside = [x for x in jizhi if x not in jizhi_filtered]

            if jizhi_outside:
                self.steps.append(
                    ["极值点 x = {} 不在区间 {} 内".format(','.join(str(x) for x in jizhi_outside), args[1].printing()), ""])

            # 求最值
            xs = FiniteSet(start, end) + FiniteSet(*jizhi_filtered)
            ys = {key: fun.expression.subs(fun.var, key) for key in xs}
            self.steps.append(
                ['所以' + ", ".join(["{}({})={}".format(fun.name, key, val) for key, val in ys.items()]), ""])

            x = self.zuizhi_func(ys, key=ys.get)
            zuizhi = self.zuizhi_func(ys.values())

            # 补充：如果取到最值
            if x in interval:
                self.steps.append(["所以函数在区间 {} 上的{}是 {}".format(args[1].printing(), self.symbol, zuizhi), ""])
            else:
                self.steps.append(["", "最值点 %s 不在区间 %s 内，所以函数不存在%s" % (zuizhi, interval, self.symbol)])
                zuizhi = None

        self.output.append(BaseNumber(zuizhi))
        self.label = {"求函数在区间上的最大值", }
        return self


class HanShuQuJianZuiXiaoZhi(HanShuQuJianZuiDaZhi):
    """"求函数在区间上的最小值"""
    zuizhi_func = min
    symbol = "最小值"


class HanShuQuJianZuiZhi(BaseFunction):
    """"求函数在区间上的最值"""

    def solver(self, *args):
        zuidazhi = HanShuQuJianZuiDaZhi().solver(*args)
        zuixiaozhi = HanShuQuJianZuiXiaoZhi().solver(*args)

        self.steps.extend(zuidazhi.steps)
        self.steps.extend(zuixiaozhi.steps)

        zuida_zuixiao = [zuidazhi.output[0].value, zuixiaozhi.output[0].value]
        self.output.append(BaseValue(zuida_zuixiao))
        self.label = {"利用导数求函数在的最值", }
        return self


if __name__ == '__main__':
    pass
